
#include "inputselector.h"

#undef max
#define max(x,y) ((x) > (y) ? (x) : (y))

void inputSelector_create(InputSelector** inputSelector)
{
    (*inputSelector) = (InputSelector*) malloc(sizeof(InputSelector));
}

void inputSelector_initialize(InputSelector* inputSelector)
{
    /*On initialise le temps à une seconde*/
    inputSelector->delay.tv_sec = 0;
    inputSelector->delay.tv_usec = 100;
    /*On intialise les différents membres*/
    dynamicArray_initialize(&inputSelector->filedescriptors);
    FD_ZERO(&inputSelector->rfds);
    pthread_mutex_init(&inputSelector->mutex,NULL);
}

void inputSelector_clear(InputSelector* inputSelector)
{
    /*On remet les différent membres à 0*/
    inputSelector->delay.tv_sec = 0;
    inputSelector->delay.tv_usec = 0;
    FD_ZERO(&inputSelector->rfds);
    /*On prend le mutex pour vider le tableau de descripteur de fichier*/
    pthread_mutex_lock(&inputSelector->mutex);
    /*On vide le tableau de descripteur de fichier*/
    dynamicArray_clear(&inputSelector->filedescriptors);
    /*On libère le mutex*/
    pthread_mutex_unlock(&inputSelector->mutex);
    /*On détruit le mutex*/
    pthread_mutex_destroy(&inputSelector->mutex);

}

void inputSelector_destroy(InputSelector** inputSelector)
{
    inputSelector_clear((*inputSelector));
    free((*inputSelector));
    (*inputSelector) = NULL;
}

void inputSelector_add(InputSelector* inputSelector, int fileDescriptor)
{
    pthread_mutex_lock(&inputSelector->mutex);
    dynamicArray_inserLast(&inputSelector->filedescriptors,(void*)fileDescriptor);
    pthread_mutex_unlock(&inputSelector->mutex);
}

int inputSelector_remove(InputSelector* inputSelector, int fileDescriptor)
{
    int ret;
    pthread_mutex_lock(&inputSelector->mutex);
    ret = dynamicArray_remove(&inputSelector->filedescriptors,(void*)fileDescriptor);
    pthread_mutex_unlock(&inputSelector->mutex);
    return ret;
}

int inputSelector_selectAndRemove(InputSelector* inputSelector, int* fileDescriptor)
{
    int i, retval, ndfs = 0;
    struct timeval empty;
    empty.tv_sec = 0;
    empty.tv_usec = 0;

    /*On met la valeur de fileDescriptor à -1*/
    *fileDescriptor = -1;

    /*On met à zéro l'ensemble de descripteurs de fichiers*/
    FD_ZERO(&inputSelector->rfds);

    /*On prend le mutex*/
    pthread_mutex_lock(&inputSelector->mutex);

    /*On ajoute l'ensemble des descripteurs de fichiers à l'ensemble*/
    for(i=0;i < inputSelector->filedescriptors.count; i++)
    {
        FD_SET((int)inputSelector->filedescriptors.array[i],&inputSelector->rfds);
        ndfs = max(ndfs,(int)inputSelector->filedescriptors.array[i]);
    }

    /*On remplit l'ensemble de descripteur de fichiers*/
    retval = select(ndfs + 1,&inputSelector->rfds,NULL,NULL,&empty);
    if(retval > 0 )
    {
        /*On parcours chaque descripteurs de fichier du tableau*/
        for(i=0;i < inputSelector->filedescriptors.count; i++)
        {
            /*Si le descripteur de fichier courant est lisible*/
            if(FD_ISSET((int)inputSelector->filedescriptors.array[i],&inputSelector->rfds))
            {
                /*On définie la valeur de retour avec le descripteur de fichier*/
                (*fileDescriptor) = (int)inputSelector->filedescriptors.array[i];
                /*On supprime le descripteur de fichier de la liste*/
                dynamicArray_remove(&inputSelector->filedescriptors,inputSelector->filedescriptors.array[i]);
                /*On interromp la boucle for*/
                break;
            }
        }
    }

    /*On libère le mutex*/
    pthread_mutex_unlock(&inputSelector->mutex);
    /*On attend*/
    select(0,NULL,NULL,NULL,&inputSelector->delay);
    inputSelector->delay.tv_sec = 0;
    inputSelector->delay.tv_usec = 10;
    /*On retourne la valeur de succès ou d'échec*/
    return (retval != -1);
}

int inputSelector_isReadable(InputSelector* inputSelector, int fileDesciptor)
{
    /*On met à zéro l'ensemble de descripteurs de fichiers*/
    FD_ZERO(&inputSelector->rfds);
    /*On ajoute le descripteur de fichier à l'ensemble*/
    FD_SET(fileDesciptor,&inputSelector->rfds);
    /*Si la valeur de retourd de select est egale au descipteur de fichier alors celui-ci est lisible*/
    return (select(fileDesciptor,&inputSelector->rfds,NULL,NULL,NULL) == fileDesciptor);
}
